package upgrade

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/sagoo-cloud/sagooiot/internal/consts"
	"github.com/sagoo-cloud/sagooiot/internal/dao"
	"github.com/sagoo-cloud/sagooiot/internal/model"
	"github.com/sagoo-cloud/sagooiot/internal/model/entity"
	"github.com/sagoo-cloud/sagooiot/internal/mqtt"
	"github.com/sagoo-cloud/sagooiot/internal/service"
)

type sUpgradeDevOtaStrategy struct{}

func sUpgradeDevOtaStrategyNew() *sUpgradeDevOtaStrategy {
	return &sUpgradeDevOtaStrategy{}
}
func init() {
	service.RegisterUpgradeDevOtaStrategy(sUpgradeDevOtaStrategyNew())
}

// GetDevOtaStrategyList 获取列表数据
func (s *sUpgradeDevOtaStrategy) GetDevOtaStrategyList(ctx context.Context, in *model.GetDevOtaStrategyListInput) (total, page int, list []*model.DevOtaStrategyOutput, err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		m := dao.DevOtaStrategy.Ctx(ctx).Where("dev_ota_fireware_id = ?", in.DevOtaFirewareId)
		if in.Name != "" {
			m = m.WhereLike(dao.DevOtaStrategy.Columns().Name, in.Name)
		}
		total, err = m.Count()
		if err != nil {
			err = gerror.New("获取总行数失败")
			return
		}
		page = in.PageNum
		if in.PageSize == 0 {
			in.PageSize = consts.PageSize
		}
		err = m.Page(page, in.PageSize).Order("created_at desc").Scan(&list)
		if err != nil {
			err = gerror.New("获取数据失败")
		}
	})
	return
}

// GetDevOtaStrategyById 获取指定ID数据
func (s *sUpgradeDevOtaStrategy) GetDevOtaStrategyById(ctx context.Context, id int) (out *model.DevOtaStrategyOutput, err error) {
	err = dao.DevOtaStrategy.Ctx(ctx).Where(dao.DevOtaStrategy.Columns().Id, id).Scan(&out)
	return
}

// AddDevOtaStrategy 添加数据
func (s *sUpgradeDevOtaStrategy) AddDevOtaStrategy(ctx context.Context, in model.DevOtaStrategyAddInput) (err error) {
	en := new(entity.DevOtaStrategy)
	gconv.Scan(in, en)
	en.Status = 1
	en.Active = 1
	lastId := int64(0)

	dao.DevOtaStrategy.Ctx(ctx).Where(dao.DevOtaStrategy.Columns().Active, 1).
		Where(dao.DevOtaStrategy.Columns().DevOtaFirewareId, in.DevOtaFirewareId).
		Update(map[string]string{"active": "0", "status": "2"})

	lastId, err = dao.DevOtaStrategy.Ctx(ctx).InsertAndGetId(en)
	if err != nil {
		return err
	}
	// 如果没有选择设备，所有设备发送
	if len(in.Devices) == 0 {
		ware, err := service.UpgradeDevOtaFireware().GetDevOtaFirewareById(ctx, in.DevOtaFirewareId)
		if err != nil {
			return err
		}
		if ware == nil {
			return gerror.New("升级包不存在")
		}
		devices := []entity.DevDevice{}
		err = dao.DevDevice.Ctx(ctx).Fields("id").Where(dao.DevDevice.Columns().ProductId, ware.ProductId).Scan(&devices)
		if err != nil {
			return err
		}
		for _, v := range devices {
			in.Devices = append(in.Devices, int(v.Id))
		}
	}

	go s.insertDevices(ctx, int(lastId), in)

	//TODO push = 1 && method =3(mqtt) 主动推送, 推送升级信息
	if in.Push == 1 && in.Method == 3 {
		go s.Issue(ctx, in.DevOtaFirewareId, int(lastId), in.Devices)
	}

	return
}

// Issue public upgrade infomation
func (s *sUpgradeDevOtaStrategy) insertDevices(ctx context.Context, lastId int, in model.DevOtaStrategyAddInput) {
	var temp int
	devices := []entity.DevOtaDetail{}
	for i := 0; i < len(in.Devices); i++ {
		dev := entity.DevOtaDetail{}
		dev.DeviceId = in.Devices[i]
		dev.StrategyId = int(lastId)
		dev.Status = 0
		dev.Step = "1"
		devices = append(devices, dev)
		temp++
		if temp == 100 {
			_, err := dao.DevOtaDetail.Ctx(ctx).Data(devices).Insert()
			if err != nil {
				g.Log().Error(ctx, fmt.Sprintf("%v+", err.Error()))
			}
			devices = devices[0:0]
			temp = 0
		}
	}
	if temp > 0 {
		_, err := dao.DevOtaDetail.Ctx(ctx).Data(devices).Insert()
		if err != nil {
			g.Log().Error(ctx, fmt.Sprintf("%v+", err.Error()))
		}
	}
}

// Issue public upgrade infomation
func (s *sUpgradeDevOtaStrategy) Issue(ctx context.Context, fireWareId, strategyId int, devices []int) (err error) {
	info := new(entity.DevOtaFireware)
	err = dao.DevOtaFireware.Ctx(ctx).Where(dao.DevOtaFireware.Columns().Id, fireWareId).Scan(&info)
	if err != nil {
		return err
	}
	product := new(entity.DevProduct)
	err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, info.ProductId).Scan(&product)
	if err != nil {
		return err
	}

	out := model.DevStrategyOut{}
	out.ExtData = g.MapStrAny{"strategy": strategyId}
	out.Url = info.OssUrl
	out.Version = info.Version // 上传的升级包版本号
	out.Module = info.Module
	out.Sign = info.Sign
	out.SignMethod = info.Are

	send := model.UpgradeOut{}
	send.Code = 200
	send.Data = out

	msg, _ := json.Marshal(send)
	g.Log().Info(ctx, " public info : ", msg)

	for _, v := range devices {

		device := new(entity.DevDevice)
		err = dao.DevDevice.Ctx(ctx).Where(dao.DevDevice.Columns().Id, v).Scan(&device)
		if err != nil {
			g.Log().Errorf(ctx, "publish fail device id : %d ", v)
			continue
		}
		topic := fmt.Sprintf(string(consts.IssueUpgradeCmd), product.Key, device.Key)
		if upgradeErr := mqtt.Publish(topic, msg); upgradeErr != nil {
			g.Log().Errorf(ctx, "publish  data error: %w,message:%s, message ignored", upgradeErr, string(msg))
			continue
		}

		// 更新为已推送
		dao.DevOtaDetail.Ctx(ctx).Where(dao.DevOtaDetail.Columns().DeviceId, v).
			Where(dao.DevOtaDetail.Columns().StrategyId, strategyId).Data(map[string]any{"status": "1"}).Update()
	}

	return nil

}

// EditDevOtaStrategy 修改数据
func (s *sUpgradeDevOtaStrategy) EditDevOtaStrategy(ctx context.Context, in model.DevOtaStrategyEditInput) (err error) {
	dao.DevOtaStrategy.Ctx(ctx).FieldsEx(dao.DevOtaStrategy.Columns().Id).Where(dao.DevOtaStrategy.Columns().Id, in.Id).OmitEmpty().Update(in)
	return
}

func (s *sUpgradeDevOtaStrategy) StopDevOtaStrategy(ctx context.Context, id, active int) (err error) {
	_, err = dao.DevOtaStrategy.Ctx(ctx).FieldsEx(dao.DevOtaStrategy.Columns().Id).Where(dao.DevOtaStrategy.Columns().Id, id).
		Data(map[string]any{"active": active}).Update()
	return
}

// DeleteDevOtaStrategy 删除数据
func (s *sUpgradeDevOtaStrategy) DeleteDevOtaStrategy(ctx context.Context, Ids []int) (err error) {
	_, err = dao.DevOtaStrategy.Ctx(ctx).Delete(dao.DevOtaStrategy.Columns().Id+" in (?)", Ids)
	return
}
